//#include <windows.h>

#include "../../window.h"
#include "window_quartz.h"

#include "../../epsilon.h"

#include "../../EpsilonInput/keyboard.h"
#include "../../EpsilonInput/mouse.h"

//#include "/Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/Headers/MacWindows.h"
//#include <MacWindows.h>
//#include <MacTypes.h>

static EventHandlerUPP g_ApplicationEventHandler;
static EventHandlerUPP g_WindowEventHandler;

static bool g_WindowEventHandler_c = false;

static pascal
OSStatus
ApplicationEventHandler (EventHandlerCallRef handler,
                         EventRef            event,
                         void*               pUserData)
{
  OSStatus result = eventNotHandledErr;

  UInt32 eventClass = GetEventClass (event);
  UInt32 eventKind  = GetEventKind  (event);

  switch (eventClass) {
    kEventClassMouse:
//      handleWindowMouseEvents (myHandler, event);
      break;
    case kEventClassCommand:
//////      printf ("Comand\n");
      break;
    case kEventCommandUpdateStatus:
//////      printf ("Command Update Status");
      result = noErr;
      break;
  }

  return result;
}

pascal
OSStatus
eWindowQuartz::GlobalEventHandler (EventHandlerCallRef handler,
                                   EventRef            event,
                                   void*               pUserData)
{
  if (pUserData != NULL)
    ((eWindowQuartz *)pUserData)->InternalEventHandler (handler, event);
  else
    printf ("Cannot dispatch Window Event! [No Window Ptr.]\n");
};

#define eKeyboard Epsilon::Keyboard
#define eMouse    Epsilon::Mouse

class eKeyboardQuartz {
public:
  static eKeyboard::Key EpsilonKey (UInt32 macKey) {
    struct MacKeyConvert {
      UInt32         MacCode;
      eKeyboard::Key Key;
    };

    static const MacKeyConvert MacToEpsilon [] = {
         { 0x00, eKeyboard::TextKey (eKeyboard::TextKeys::A) },
   { 0x01, eKeyboard::TextKey (eKeyboard::TextKeys::S) },
   { 0x02, eKeyboard::TextKey (eKeyboard::TextKeys::D) },
   { 0x03, eKeyboard::TextKey (eKeyboard::TextKeys::F) },
   { 0x04, eKeyboard::TextKey (eKeyboard::TextKeys::H) },
   { 0x05, eKeyboard::TextKey (eKeyboard::TextKeys::G) },
   { 0x06, eKeyboard::TextKey (eKeyboard::TextKeys::Z) },
   { 0x07, eKeyboard::TextKey (eKeyboard::TextKeys::X) },
   { 0x08, eKeyboard::TextKey (eKeyboard::TextKeys::C) },
   { 0x09, eKeyboard::TextKey (eKeyboard::TextKeys::V) },
   { 0x0B, eKeyboard::TextKey (eKeyboard::TextKeys::B) },
   { 0x0C, eKeyboard::TextKey (eKeyboard::TextKeys::Q) },
   { 0x0D, eKeyboard::TextKey (eKeyboard::TextKeys::W) },
   { 0x0E, eKeyboard::TextKey (eKeyboard::TextKeys::E) },
   { 0x0F, eKeyboard::TextKey (eKeyboard::TextKeys::R) },
   { 0x10, eKeyboard::TextKey (eKeyboard::TextKeys::Y) },
   { 0x11, eKeyboard::TextKey (eKeyboard::TextKeys::T) },
   { 0x12, eKeyboard::TextKey (eKeyboard::TextKeys::One) },
   { 0x13, eKeyboard::TextKey (eKeyboard::TextKeys::Two) },
   { 0x14, eKeyboard::TextKey (eKeyboard::TextKeys::Three) },
   { 0x15, eKeyboard::TextKey (eKeyboard::TextKeys::Four) },
   { 0x16, eKeyboard::TextKey (eKeyboard::TextKeys::Six) },
   { 0x17, eKeyboard::TextKey (eKeyboard::TextKeys::Five) },
   { 0x18, eKeyboard::TextKey (eKeyboard::TextKeys::Equals) },
   { 0x19, eKeyboard::TextKey (eKeyboard::TextKeys::Nine) },
   { 0x1A, eKeyboard::TextKey (eKeyboard::TextKeys::Seven) },
   { 0x1B, eKeyboard::TextKey (eKeyboard::TextKeys::Minus) },
   { 0x1C, eKeyboard::TextKey (eKeyboard::TextKeys::Eight) },
   { 0x1D, eKeyboard::TextKey (eKeyboard::TextKeys::Zero) },
   { 0x1E, eKeyboard::TextKey (eKeyboard::TextKeys::RightBracket) },
   { 0x1F, eKeyboard::TextKey (eKeyboard::TextKeys::O) },
   { 0x20, eKeyboard::TextKey (eKeyboard::TextKeys::U) },
   { 0x21, eKeyboard::TextKey (eKeyboard::TextKeys::LeftBracket) },
   { 0x22, eKeyboard::TextKey (eKeyboard::TextKeys::I) },
   { 0x23, eKeyboard::TextKey (eKeyboard::TextKeys::P) },
   { 0x24, eKeyboard::MiscKey (eKeyboard::MiscKeys::Enter) },
   { 0x25, eKeyboard::TextKey (eKeyboard::TextKeys::L) },
   { 0x26, eKeyboard::TextKey (eKeyboard::TextKeys::J) },
   { 0x27, eKeyboard::TextKey (eKeyboard::TextKeys::Quote) },
   { 0x28, eKeyboard::TextKey (eKeyboard::TextKeys::K) },
   { 0x29, eKeyboard::TextKey (eKeyboard::TextKeys::SemiColon) },
   { 0x2A, eKeyboard::TextKey (eKeyboard::TextKeys::BackSlash) },
   { 0x2B, eKeyboard::TextKey (eKeyboard::TextKeys::Comma) },
   { 0x2C, eKeyboard::TextKey (eKeyboard::TextKeys::Slash) },
   { 0x2D, eKeyboard::TextKey (eKeyboard::TextKeys::N) },
   { 0x2E, eKeyboard::TextKey (eKeyboard::TextKeys::M) },
   { 0x2F, eKeyboard::TextKey (eKeyboard::TextKeys::Period) },
   { 0x30, eKeyboard::MiscKey (eKeyboard::MiscKeys::Tab ) },
   { 0x31, eKeyboard::MiscKey (eKeyboard::MiscKeys::Space) },
   { 0x32, eKeyboard::TextKey (eKeyboard::TextKeys::WHATTHEHELL) }, // `) ?
   { 0x33, eKeyboard::MiscKey (eKeyboard::MiscKeys::Backspace) },
///    0x34,   IBook Enter
         { 0x35, eKeyboard::MiscKey (eKeyboard::MiscKeys::Escape) },

   { 0x41, eKeyboard::MiscKey (eKeyboard::MiscKeys::NumPad_Period) },
   { 0x43, eKeyboard::MiscKey (eKeyboard::MiscKeys::NumPad_Multiply) },
   { 0x45, eKeyboard::MiscKey (eKeyboard::MiscKeys::NumPad_Plus) },
   { 0x4B, eKeyboard::MiscKey (eKeyboard::MiscKeys::NumPad_Divide) },
   { 0x4C, eKeyboard::MiscKey (eKeyboard::MiscKeys::NumPad_Enter) },
   { 0x4E, eKeyboard::MiscKey (eKeyboard::MiscKeys::NumPad_Minus) },
   { 0x51, eKeyboard::MiscKey (eKeyboard::MiscKeys::NumPad_Equals) },
   { 0x52, eKeyboard::MiscKey (eKeyboard::MiscKeys::NumPad_0) },
   { 0x53, eKeyboard::MiscKey (eKeyboard::MiscKeys::NumPad_1) },
   { 0x54, eKeyboard::MiscKey (eKeyboard::MiscKeys::NumPad_2) },
   { 0x55, eKeyboard::MiscKey (eKeyboard::MiscKeys::NumPad_3) },
   { 0x56, eKeyboard::MiscKey (eKeyboard::MiscKeys::NumPad_4) },
   { 0x57, eKeyboard::MiscKey (eKeyboard::MiscKeys::NumPad_5) },
   { 0x58, eKeyboard::MiscKey (eKeyboard::MiscKeys::NumPad_6) },
   { 0x59, eKeyboard::MiscKey (eKeyboard::MiscKeys::NumPad_7) },
   { 0x5B, eKeyboard::MiscKey (eKeyboard::MiscKeys::NumPad_8) },
   { 0x5C, eKeyboard::MiscKey (eKeyboard::MiscKeys::NumPad_9) },

   { 0x60, eKeyboard::MiscKey (eKeyboard::MiscKeys::F5) },
   { 0x61, eKeyboard::MiscKey (eKeyboard::MiscKeys::F6) },
   { 0x62, eKeyboard::MiscKey (eKeyboard::MiscKeys::F7) },
   { 0x63, eKeyboard::MiscKey (eKeyboard::MiscKeys::F3) },
   { 0x64, eKeyboard::MiscKey (eKeyboard::MiscKeys::F8) },
   { 0x65, eKeyboard::MiscKey (eKeyboard::MiscKeys::F9) },
//    0x66
   { 0x67, eKeyboard::MiscKey (eKeyboard::MiscKeys::F11) },
//    0x68
   { 0x69, eKeyboard::MiscKey (eKeyboard::MiscKeys::Print) },
//   { 0x6A, eKeyboard::MiscKey (eKeyboard::MiscKeys::F16) },
   { 0x6B, eKeyboard::MiscKey (eKeyboard::MiscKeys::ScrollLock) },
//    0x6C
   { 0x6D, eKeyboard::MiscKey (eKeyboard::MiscKeys::F10) },
//    0x6E
   { 0x6F, eKeyboard::MiscKey (eKeyboard::MiscKeys::F12) },
//    0x70
   { 0x71, eKeyboard::MiscKey (eKeyboard::MiscKeys::Pause) },
   { 0x72, eKeyboard::MiscKey (eKeyboard::MiscKeys::Insert) },
   { 0x73, eKeyboard::MiscKey (eKeyboard::MiscKeys::Home) },
   { 0x74, eKeyboard::MiscKey (eKeyboard::MiscKeys::PageUp) },
   { 0x75, eKeyboard::MiscKey (eKeyboard::MiscKeys::Delete) },
   { 0x76, eKeyboard::MiscKey (eKeyboard::MiscKeys::F4) },
   { 0x77, eKeyboard::MiscKey (eKeyboard::MiscKeys::End) },
   { 0x78, eKeyboard::MiscKey (eKeyboard::MiscKeys::F2) },
   { 0x79, eKeyboard::MiscKey (eKeyboard::MiscKeys::PageDown) },
   { 0x7A, eKeyboard::MiscKey (eKeyboard::MiscKeys::F1) },
   { 0x7B, eKeyboard::MiscKey (eKeyboard::MiscKeys::Left) },
   { 0x7C, eKeyboard::MiscKey (eKeyboard::MiscKeys::Right) },
   { 0x7D, eKeyboard::MiscKey (eKeyboard::MiscKeys::Down) },
   { 0x7E, eKeyboard::MiscKey (eKeyboard::MiscKeys::Up) }
   };

     for (unsigned int i = 0; i < sizeof (MacToEpsilon) / sizeof (MacKeyConvert); i++)
     {
       if (MacToEpsilon [i].MacCode == macKey)
         return MacToEpsilon [i].Key;
     }

     return eKeyboard::Key (0, eKeyboard::_NUM_KEY_TYPES);
  }
};

void
print_modifier_combo (UInt32& keys)
{
  if (keys & Epsilon::Keyboard::ModifierKeys::Fn)
    printf ("(Fn) ");
  if (keys & Epsilon::Keyboard::ModifierKeys::NumLock)
    printf ("(Num Lock) ");
  if (keys & Epsilon::Keyboard::ModifierKeys::CapsLock)
    printf ("(Caps Lock) ");

  if (keys & Epsilon::Keyboard::ModifierKeys::Control)
    printf ("(Control) ");
  if (keys & Epsilon::Keyboard::ModifierKeys::Alt)
    printf ("(Option) ");
  if (keys & Epsilon::Keyboard::ModifierKeys::Command)
    printf ("(Command) ");
  if (keys & Epsilon::Keyboard::ModifierKeys::Shift)
    printf ("(Shift) ");
  printf ("\n");
}

pascal OSStatus
eWindowQuartz::InternalEventHandler (EventHandlerCallRef handler,
                                     EventRef            event)
{
  WindowRef wnd = NULL;

  OSStatus  result = eventNotHandledErr;

  UInt32    event_class = GetEventClass (event);
  UInt32    event_kind  = GetEventKind  (event);

  switch (event_class)
  {
    case kEventClassMouse:
    {
      CGPoint pos;
      CGPoint delta;
      GetEventParameter (event, kEventParamMouseLocation, typeHIPoint, NULL, sizeof (HIPoint), NULL, &pos);
      GetEventParameter (event, kEventParamMouseDelta,    typeHIPoint, NULL, sizeof (HIPoint), NULL, &delta);

      EventMouseButton button;
      GetEventParameter (event, kEventParamMouseButton,   typeMouseButton, NULL, sizeof (EventMouseButton), NULL, &button);


      switch (event_kind)
      {
        case kEventMouseDown:
        {
          switch (button)
          {
            case kEventMouseButtonPrimary:
              mouse->PressButton (eMouse::Buttons::Primary);
              break;
            case kEventMouseButtonSecondary:
              mouse->PressButton (eMouse::Buttons::Secondary);
              break;
            default:
              printf ("Mouse Button Pressed\n");
              break;
          }
        } break;
        case kEventMouseUp:
        {
          switch (button)
          {
            case kEventMouseButtonPrimary:
              mouse->ReleaseButton (eMouse::Buttons::Primary);
              break;
            case kEventMouseButtonSecondary:
              mouse->ReleaseButton (eMouse::Buttons::Secondary);
              break;
            default:
              printf ("Mouse Button Released\n");
              break;
          }
        } break;
        case kEventMouseMoved:
        case kEventMouseDragged:
        {
          HIPoint pos_rel;
          pos_rel.x = pos.x - wndRect.rcClient.left;
          pos_rel.y = pos.y - wndRect.rcClient.top;
//          printf ("Mouse Moved... (%f, %f)  [Delta: (%f, %f)\n", pos_rel.x, pos_rel.y,  delta.x, delta.y);

          mouse->MoveCursor      (pos_rel.x, pos_rel.y, true);
          mouse->MoveCursorDelta (delta.x,  delta.y,    false);

          //mouse->x_ = pos_rel.x;
          //mouse->y_ = pos_rel.y;

          ////mouse->delta_x_ = delta.x;
          ////mouse->delta_y_ = delta.y;
        }
        break;
      }
    }
    break;
    //
    // Keyboard Events
    //
    case kEventClassKeyboard:
    {
      UInt32 keyCode;
      eKeyboard::Key key;

      GetEventParameter (event, kEventParamKeyCode, typeUInt32, NULL, sizeof (UInt32), NULL, &keyCode);

      switch (event_kind)
      {
        case kEventRawKeyDown:
          key = eKeyboardQuartz::EpsilonKey (keyCode);

          if (key.getType () == eKeyboard::_NUM_KEY_TYPES)
            printf ("Pressed a key... ");

          if (keyboard)
            keyboard->PressKey (key);
//          result = handleKeyInput (handler, event, true, userData);
          break;
        case kEventRawKeyUp:
          key = eKeyboardQuartz::EpsilonKey (keyCode);

          if (key.getType () == eKeyboard::_NUM_KEY_TYPES)
            printf ("Released a key... ");

          if (keyboard)
            keyboard->ReleaseKey (key);
//          result = handleKeyInput (handler, event, false, userData);
          break;
        case kEventRawKeyModifiersChanged:
                GetEventParameter (event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof (UInt32), NULL, &keyCode);
//          print_modifier_combo (keyCode);
          key = eKeyboard::Key (keyCode, eKeyboard::Modifier);
          keyboard->PressKey (key);
          break;
        default:
          /// Unknown Event
          break;
      }
      if (key.getType () == eKeyboard::_NUM_KEY_TYPES)
        printf ("KeyCode: %lu (0x%lX)\n", keyCode, keyCode);
    }
    break;

    //
    // Window Events
  //
    case kEventClassWindow:
      GetEventParameter (event, kEventParamDirectObject, typeWindowRef, NULL, sizeof (WindowRef), NULL, &wnd);
      
      switch (event_kind) {
        case kEventWindowCollapsing:
          /// XXX: TODO
          break;
        case kEventWindowDeactivated:
          deactivate (); /// Window Internals
          if (keyboard)
            keyboard->ResetKeys ();
//          printf ("Deactivated!\n");
          SetUserFocusWindow (NULL);
          CGDisplayShowCursor (0);
          break;
        case kEventWindowActivated:
          activate (); /// Window Internals
          CGDisplayHideCursor (0);
//          printf ("Activated!\n");
          SetUserFocusWindow (wnd);
          break;
        case kEventWindowClose:
          printf ("Window Closed!\n");
          break;
        case kEventWindowDrawContent:
          break;
        case kEventWindowShown:
          break;
        case kEventWindowBoundsChanged:
          update_rect ();

          if (window->wndListener)
            window->wndListener->OnMove (wndRect);
          else if (window->wndMoveCallback)
            window->wndMoveCallback (window, wndRect);
          break;
        case kEventWindowZoomed:
        case kEventWindowResizeCompleted:
          update_rect ();

          if (window->wndListener)
            window->wndListener->OnResize (wndRect);
          else if (window->wndResizeCallback)
            window->wndResizeCallback (window, wndRect);

          break;
        default:
//          printf ("Misc. Window Event!\n");
          break;
      }
      break;
  }

  return result;
}


bool
eWindowQuartz::create (const eWindowParameters& parameters, eWindow* window)
{
  /// TODO: This should only happen once
  if (! g_WindowEventHandler_c) {
    g_WindowEventHandler = NewEventHandlerUPP (eWindowQuartz::GlobalEventHandler);
    g_WindowEventHandler_c = true;

//g_ApplicationEventHandler = NewEventHandlerUPP (ApplicationEventHandler);
    ProcessSerialNumber psn = { 0, kCurrentProcess };
    TransformProcessType (&psn, kProcessTransformToForegroundApplication);

    CGAssociateMouseAndMouseCursorPosition (true);
  }

  initialized = false;

  this->window = window;

  OSStatus err;

  Rect bounds;

  bounds.top  = 0;
  bounds.left = 0;
  bounds.bottom = parameters.window_height;
  bounds.right  = parameters.window_width;

  err = CreateNewWindow (kDocumentWindowClass,
                         ( kWindowStandardHandlerAttribute |
                           kWindowLiveResizeAttribute      |
                           kWindowStandardDocumentAttributes ),
                         &bounds,
                         &wndref);

  if (keyboard == NULL)
    keyboard = new eKeyboard ();

  if (mouse == NULL)
    mouse = new eMouse ();

  /// TODO: Make this into a function: SetTitle (...)
  CFStringRef title = CFStringCreateWithCString (NULL, parameters.window_name, kCFStringEncodingASCII);
  SetWindowTitleWithCFString (wndref, title);

  EventHandlerRef ref;
  EventTypeSpec list [] =  { { kEventClassWindow, kEventWindowCollapsing },
                             { kEventClassWindow, kEventWindowShown },
                             { kEventClassWindow, kEventWindowActivated },
                             { kEventClassWindow, kEventWindowDeactivated },
                             { kEventClassWindow, kEventWindowClose },
                             { kEventClassWindow, kEventWindowDrawContent },
                             { kEventClassWindow, kEventWindowBoundsChanged },
                             { kEventClassWindow, kEventWindowBoundsChanging },
                             { kEventClassWindow, kEventWindowZoomed },
                             { kEventClassWindow, kEventWindowTransitionStarted },
                             { kEventClassWindow, kEventWindowTransitionCompleted },
                             { kEventClassWindow, kEventWindowResizeStarted },
                             { kEventClassWindow, kEventWindowResizeCompleted },
                             { kEventClassWindow, kEventWindowClickResizeRgn },
                             { kEventClassKeyboard, kEventRawKeyDown },
                             { kEventClassKeyboard, kEventRawKeyUp },
                             { kEventClassKeyboard, kEventRawKeyModifiersChanged },
                             { kEventClassMouse, kEventMouseMoved },
                             { kEventClassMouse, kEventMouseDragged },
                             { kEventClassMouse, kEventMouseDown },
                             { kEventClassMouse, kEventMouseUp } };



  InstallWindowEventHandler (wndref, g_WindowEventHandler, GetEventTypeCount (list), list, (void *)this, &ref);
//  InstallApplicationEventHandler (g_ApplicationEventHandler, GetEventTypeCount (list), list, 0, &ref);

//  Assert (dpy != NULL, _T ("Display did not open..."));


  /// TODO: Make this a window parameter
  HISize minimumWindowSize;
  minimumWindowSize = CGSizeMake (150, 64);
  SetWindowResizeLimits (wndref, &minimumWindowSize, NULL);

  show (true);
  SetUserFocusWindow (wndref);

  initialized = true;

  update_rect ();

  return true;
}

bool
eWindowQuartz::destroy (void)
{
  initialized = false;

  // TODO
  return true;
}





void
eWindowQuartz::Think (void)
{
#if 1
  while (true) // Run until no events are queued
  {
    EventRef       event;
    EventTargetRef target;

    OSStatus status;

    target = GetEventDispatcherTarget ();
    
    int i = 0;
    while ((status = ReceiveNextEvent (0, 0, 0, true, &event)) == noErr)
    {
      UInt32 event_class = GetEventClass (event);
      UInt32 event_kind  = GetEventKind  (event);

      if (event_class == kEventClassWindow)
      {
//        printf ("Window Event #%d :: < %d>!\n", ++i, event_kind);
      }
      if (event_class == kEventClassApplication) {
        if (event_kind == kEventAppActivated) {
//////          printf ("App. Activated!\n");

          WindowRef wndRef;
          GetEventParameter (event, kEventParamWindowRef, typeWindowRef, NULL, sizeof (WindowRef), NULL, &wndRef);

//////          if (wndRef == NULL)
//////            printf ("Uh oh!\n");

//          SetUserFocusWindow (wndRef);
        }
        else if (event_kind == kEventAppDeactivated) {
//////          printf ("App. Deactivated!\n");

          SetUserFocusWindow (NULL);
        }
//////        else
//////          printf ("Application Event: %d :: < %d>!\n", ++i, event_kind);
      }
////      else
////        printf ("Event #%d :: [%d - %d]!\n", ++i, event_class, event_kind);

      SendEventToEventTarget (event, target);
        ReleaseEvent (event);
    }
    break;
  }
#else
  RunApplicationEventLoop ();
#endif

/*
  XEvent event; // X Event Structure

  while (true) // Run until no events are queued
  {
    // Is There An Event Queued?
    if (XEventsQueued (::dpy, QueuedAfterFlush)) {
      XNextEvent (::dpy, &event);

      switch (event.type) {
        case ButtonPress:
        case ButtonRelease:
          eMessageBox (_T ("Button Event"));
          break;
        case KeyPress:
        case KeyRelease:
          eMessageBox (_T ("Key Event"));
          break;
        case MotionNotify:
          eMessageBox (_T ("Motion Notify Event"));
          break;
        case ResizeRequest:
          eMessageBox (_T ("Resize Request Event"));
          break;
        case FocusIn:
        case FocusOut:
          eMessageBox (_T ("Focus Change Event"));
          break;
        default:
          eMessageBox (_T ("Unknown Event"));
          break;
      };
    } else {
      return;
    }
  }
*/
}




void
eWindowQuartz::move (const int& left, const int& top)
{
  // NOTE: This moves the Window to the specified coords (the client region may
  //       be offset by a couple of pixels depending on the window style.
  if (initialized)
    MoveWindow (wndref, left, top, false);
}

void
eWindowQuartz::move_client (const int& left, const int& top)
{
  // Compensate for window borders, and move the client rect to the specified
  // position.
  if (initialized) {
    update_rect ();

    int x_offset = wndRect.rcWindow.left - wndRect.rcClient.left;
    int y_offset = wndRect.rcWindow.top  - wndRect.rcClient.top;

    MoveWindow (wndref, left, top, false);
//    SetWindowPos (hWndRender, NULL, left + x_offset, top + y_offset, 0, 0, SWP_NOSIZE);
  }
}

void
eWindowQuartz::resize (const int& x,    const int& y)
{
  if (initialized)
    SizeWindow (wndref, x, y, true);
}

void
eWindowQuartz::resize_client (const int& x,    const int& y)
{
  // Set the window rect (includes borders) to match the current client rect.
  memcpy (&wndRect.rcWindow, &wndRect.rcClient, sizeof (eRect));
  
  // Resize the client rect
  wndRect.rcWindow.right  = wndRect.rcWindow.left + x;
  wndRect.rcWindow.bottom = wndRect.rcWindow.top  + y;

  // Adjust the window rect to compensate for borders
//  AdjustWindowRectEx ((tagRECT *)&wndRect.rcWindow, dwStyle, false, dwExStyle);

  // Calculate the required number of pixels to resize the WINDOW to get the
  // desired CLIENT rect.
  int adj_x = wndRect.rcWindow.right  - wndRect.rcWindow.left;
  int adj_y = wndRect.rcWindow.bottom - wndRect.rcWindow.top;

  if (initialized)
    SizeWindow (wndref, x, y, true);
}

/// TODO: Act on the value of the input ...
void eWindowQuartz::show (int)
{
  ShowWindow (wndref);
  return;
}

/// TODO: Finish Implementing
bool eWindowQuartz::recreate (const eWindowParameters& params)
{
  SizeWindow (wndref, params.window_width, params.window_height, true);

  CFStringRef title = CFStringCreateWithCString (NULL, params.window_name, kCFStringEncodingASCII);
  SetWindowTitleWithCFString (wndref, title);

  return true;
}


void
eWindowQuartz::update_rect (void)
{
  // Don't care about invalid update_rect's when the window isn't initialized.
//  if (! initialized)
//    return;

  Rect rectClient;
  Rect rectWindow;

  GetWindowBounds (wndref, kWindowContentRgn, &rectClient);
  GetWindowBounds (wndref, kWindowOpaqueRgn,  &rectWindow);

//  memcpy (&wndRect.rcClient, &rectPort, sizeof (wndRect.rcClient));
//  memcpy (&wndRect.rcWindow, &rectPort, sizeof (wndRect.rcWindow));

  wndRect.rcClient.bottom = rectClient.bottom;
  wndRect.rcClient.top    = rectClient.top;
  wndRect.rcClient.left   = rectClient.left;
  wndRect.rcClient.right  = rectClient.right;

  wndRect.rcWindow.bottom = rectWindow.bottom;
  wndRect.rcWindow.top    = rectWindow.top;
  wndRect.rcWindow.left   = rectWindow.left;
  wndRect.rcWindow.right  = rectWindow.right;

  wndRect.cxWindowBorders = 0;//info.cxWindowBorders;
  wndRect.cyWindowBorders = 0;//info.cyWindowBorders;
}


const eWindowHandle
eWindowQuartz::getNativeWindowHandle (void)
{
  return eWindowHandle ((DWORD)wndref, window/*wndref*/);
}

void
eWindowQuartz::show_cursor (bool show)
{
  cursorShown = show;

  if (cursorShown)
    CGDisplayShowCursor (0);
  else
    CGDisplayHideCursor (0);
}

void
eWindowQuartz::set_cursor_pos (int x, int y)
{
  CGPoint point;
  point.x = (float)x + wndRect.rcWindow.left;
  point.y = (float)y + wndRect.rcWindow.top;

  //CGDisplayMoveCursorToPoint (0, point);
  CGWarpMouseCursorPosition (point); // Do not generate an event
  //SetCursorPos ( x + wndRect.rcClient.left,
  //               y + wndRect.rcClient.top );

  mouse->MoveCursor      (x,        y,       false);
  mouse->MoveCursorDelta (0,        0,       false);

}
